package cn.seqdata.jdbc;

import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.LocalTime;
import org.springframework.jdbc.core.RowMapper;

import javax.persistence.Column;
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;

public class JpaFieldMapper<T> implements RowMapper<T> {
	private final Class<T> klass;

	public JpaFieldMapper(Class<T> klass) {
		this.klass = klass;
	}

	@Override
	public T mapRow(ResultSet rs, int rowNum) throws SQLException {
		try {
			T instance = klass.newInstance();

			for(Field field : klass.getFields()) {
				Column column = field.getAnnotation(Column.class);
				String columnName = column.name();
				Class<?> fieldType = field.getType();

				if(int.class.equals(fieldType)) {
					field.set(instance, rs.getInt(columnName));
				} else if(long.class.equals(fieldType)) {
					field.set(instance, rs.getLong(columnName));
				} else if(float.class.equals(fieldType)) {
					field.set(instance, rs.getFloat(columnName));
				} else if(double.class.equals(fieldType)) {
					field.set(instance, rs.getDouble(columnName));
				} else if(boolean.class.equals(fieldType)) {
					field.set(instance, rs.getBoolean(columnName));
				} else if(Integer.class.equals(fieldType)) {
					field.set(instance, JdbcUtils.getInteger(rs, columnName));
				} else if(Long.class.equals(fieldType)) {
					field.set(instance, JdbcUtils.getLong(rs, columnName));
				} else if(Float.class.equals(fieldType)) {
					field.set(instance, JdbcUtils.getFloatObject(rs, columnName));
				} else if(Double.class.equals(fieldType)) {
					field.set(instance, JdbcUtils.getDoubleObject(rs, columnName));
				} else if(Boolean.class.equals(fieldType)) {
					field.set(instance, JdbcUtils.getBoolean(rs, columnName));
				} else if(Date.class.equals(fieldType)) {
					field.set(instance, rs.getDate(columnName));
				} else if(String.class.equals(fieldType)) {
					field.set(instance, rs.getString(columnName));
				} else if(DateTime.class.equals(fieldType)) {
					Timestamp val = rs.getTimestamp(columnName);
					field.set(instance, JodaUtils.toDateTime(val));
				} else if(LocalDate.class.equals(fieldType)) {
					java.sql.Date val = rs.getDate(columnName);
					field.set(instance, JodaUtils.toLocalDate(val));
				} else if(LocalTime.class.equals(fieldType)) {
					java.sql.Time val = rs.getTime(columnName);
					field.set(instance, JodaUtils.toLocalTime(val));
				} else if(LocalDateTime.class.equals(fieldType)) {
					Timestamp val = rs.getTimestamp(columnName);
					field.set(instance, JodaUtils.toLocalDateTime(val));
				}
			}

			return instance;
		} catch(ReflectiveOperationException ex) {
			throw new SQLException(ex);
		}
	}
}
